#include <keyboard.h>
#include <8259A.h>
#include <ring.h>


#define IS_E0(key)          (0xE0 == (key)) // 是否是 E0 扩展键
#define IS_E1(key)          (0xE1 == (key)) // 是否是 E1 扩展键

#define RELEASE             0               // 按键释放
#define PRESSED             1               // 按键按下
#define KEY_TYPE(key)       ((key)&0x80 ? RELEASE : PRESSED) // 0:release; 1:pressed

#define SCAN_CODE_SHIFT_L   0x2A            // 左 Shift 键扫描码
#define SCAN_CODE_SHIFT_R   0x36            // 右 Shift 键扫描码
#define SCAN_CODE_CAPSLOCK  0x3A            // CapsLock 键扫描码
#define SCAN_CODE_NUMLOCK   0x45            // NumLock  键扫描码

#define IS_SHIFT(key)       (SCAN_CODE_SHIFT_L == (key) || SCAN_CODE_SHIFT_R == (key))  // 是否是 Shift 键
#define IS_CAPSLOCK(key)    (SCAN_CODE_CAPSLOCK == (key))                               // 是否是 CapsLock 键
#define IS_NUMLOCKS(key)    (SCAN_CODE_NUMLOCK == (key))    

#define NUM_KEY0            0x52
#define NUM_KEY1            0x4F
#define NUM_KEY2            0x50
#define NUM_KEY3            0x51
#define NUM_KEY4            0x4B
#define NUM_KEY5            0x4C
#define NUM_KEY6            0x4D
#define NUM_KEY7            0x47
#define NUM_KEY8            0x48
#define NUM_KEY9            0x49

// 是否是数字键 '0' ~ '9'
#define IS_NUM_KEY(key)     ( NUM_KEY0 == (key) || NUM_KEY1 == (key) || NUM_KEY2 == (key)    \
                           || NUM_KEY3 == (key) || NUM_KEY4 == (key) || NUM_KEY5 == (key)    \
                           || NUM_KEY6 == (key) || NUM_KEY7 == (key) || NUM_KEY8 == (key)    \
                           || NUM_KEY9 == (key))

#define RING_BUF_SIZE 32

typedef struct RingQueue 
{
    U32 head;					// 循环队列缓冲区中数据头指针
    U32 tail;					// 循环队列缓冲区中数据尾指针
    U32 len;                    // 循环队列缓冲区数据长度
    U08 buf[RING_BUF_SIZE];     // 循环队列的缓冲区
} RingQueue;

static RingQueue keyQueue;      // 按键循环队列


typedef struct KEY_CODE
{
    U08 ascii1;   // 常规状态下按键 ascii 码
    U08 ascii2;   // 按下 Shift 后 ascii 码
    U08 scode;    // 扫描码
    U08 vcode;    // 虚拟键码
} KEY_CODE;

static const KEY_CODE KeyMap[] = 
{
/* 0x00 - none      */ {  0,        0,        0,         0   },
/* 0x01 - ESC       */ {  0,        0,       0x01,      0x1B },
/* 0x02 - '1'       */ { '1',      '!',      0x02,      0x31 },
/* 0x03 - '2'       */ { '2',      '@',      0x03,      0x32 },
/* 0x04 - '3'       */ { '3',      '#',      0x04,      0x33 },
/* 0x05 - '4'       */ { '4',      '$',      0x05,      0x34 },
/* 0x06 - '5'       */ { '5',      '%',      0x06,      0x35 },
/* 0x07 - '6'       */ { '6',      '^',      0x07,      0x36 },
/* 0x08 - '7'       */ { '7',      '&',      0x08,      0x37 },
/* 0x09 - '8'       */ { '8',      '*',      0x09,      0x38 },
/* 0x0A - '9'       */ { '9',      '(',      0x0A,      0x39 },
/* 0x0B - '0'       */ { '0',      ')',      0x0B,      0x30 },
/* 0x0C - '-'       */ { '-',      '_',      0x0C,      0xBD },
/* 0x0D - '='       */ { '=',      '+',      0x0D,      0xBB },
/* 0x0E - BS        */ {  0,        0,       0x0E,      0x08 },
/* 0x0F - TAB       */ {  0,        0,       0x0F,      0x09 },
/* 0x10 - 'q'       */ { 'q',      'Q',      0x10,      0x51 },
/* 0x11 - 'w'       */ { 'w',      'W',      0x11,      0x57 },
/* 0x12 - 'e'       */ { 'e',      'E',      0x12,      0x45 },
/* 0x13 - 'r'       */ { 'r',      'R',      0x13,      0x52 },
/* 0x14 - 't'       */ { 't',      'T',      0x14,      0x54 },
/* 0x15 - 'y'       */ { 'y',      'Y',      0x15,      0x59 },
/* 0x16 - 'u'       */ { 'u',      'U',      0x16,      0x55 },
/* 0x17 - 'i'       */ { 'i',      'I',      0x17,      0x49 },
/* 0x18 - 'o'       */ { 'o',      'O',      0x18,      0x4F },
/* 0x19 - 'p'       */ { 'p',      'P',      0x19,      0x50 },
/* 0x1A - '['       */ { '[',      '{',      0x1A,      0xDB },
/* 0x1B - ']'       */ { ']',      '}',      0x1B,      0xDD },
/* 0x1C - CR/LF     */ {  0,        0,       0x1C,      0x0D },
/* 0x1D - l. Ctrl   */ {  0,        0,       0x1D,      0x11 },
/* 0x1E - 'a'       */ { 'a',      'A',      0x1E,      0x41 },
/* 0x1F - 's'       */ { 's',      'S',      0x1F,      0x53 },
/* 0x20 - 'd'       */ { 'd',      'D',      0x20,      0x44 },
/* 0x21 - 'f'       */ { 'f',      'F',      0x21,      0x46 },
/* 0x22 - 'g'       */ { 'g',      'G',      0x22,      0x47 },
/* 0x23 - 'h'       */ { 'h',      'H',      0x23,      0x48 },
/* 0x24 - 'j'       */ { 'j',      'J',      0x24,      0x4A },
/* 0x25 - 'k'       */ { 'k',      'K',      0x25,      0x4B },
/* 0x26 - 'l'       */ { 'l',      'L',      0x26,      0x4C },
/* 0x27 - ';'       */ { ';',      ':',      0x27,      0xBA },
/* 0x28 - '\''      */ { '\'',     '\"',     0x28,      0xDE },
/* 0x29 - '`'       */ { '`',      '~',      0x29,      0xC0 },
/* 0x2A - l. SHIFT  */ {  0,        0,       0x2A,      0x10 },
/* 0x2B - '\'       */ { '\\',     '|',      0x2B,      0xDC },
/* 0x2C - 'z'       */ { 'z',      'Z',      0x2C,      0x5A },
/* 0x2D - 'x'       */ { 'x',      'X',      0x2D,      0x58 },
/* 0x2E - 'c'       */ { 'c',      'C',      0x2E,      0x43 },
/* 0x2F - 'v'       */ { 'v',      'V',      0x2F,      0x56 },
/* 0x30 - 'b'       */ { 'b',      'B',      0x30,      0x42 },
/* 0x31 - 'n'       */ { 'n',      'N',      0x31,      0x4E },
/* 0x32 - 'm'       */ { 'm',      'M',      0x32,      0x4D },
/* 0x33 - ','       */ { ',',      '<',      0x33,      0xBC },
/* 0x34 - '.'       */ { '.',      '>',      0x34,      0xBE },
/* 0x35 - '/'       */ { '/',      '?',      0x35,      0xBF },
/* 0x36 - r. SHIFT  */ {  0,        0,       0x36,      0x10 },
/* 0x37 - '*'       */ { '*',      '*',      0x37,      0x6A },
/* 0x38 - ALT       */ {  0,        0,       0x38,      0x12 },
/* 0x39 - ' '       */ { ' ',      ' ',      0x39,      0x20 },
/* 0x3A - CapsLock  */ {  0,        0,       0x3A,      0x14 },
/* 0x3B - F1        */ {  0,        0,       0x3B,      0x70 },
/* 0x3C - F2        */ {  0,        0,       0x3C,      0x71 },
/* 0x3D - F3        */ {  0,        0,       0x3D,      0x72 },
/* 0x3E - F4        */ {  0,        0,       0x3E,      0x73 },
/* 0x3F - F5        */ {  0,        0,       0x3F,      0x74 },
/* 0x40 - F6        */ {  0,        0,       0x40,      0x75 },
/* 0x41 - F7        */ {  0,        0,       0x41,      0x76 },
/* 0x42 - F8        */ {  0,        0,       0x42,      0x77 },
/* 0x43 - F9        */ {  0,        0,       0x43,      0x78 },
/* 0x44 - F10       */ {  0,        0,       0x44,      0x79 },
/* 0x45 - NumLock   */ {  0,        0,       0x45,      0x90 },
/* 0x46 - ScrLock   */ {  0,        0,       0x46,      0x91 },
/* 0x47 - Home      */ {  0,        0,       0x47,      0x24 },
/* 0x48 - Up        */ {  0,        0,       0x48,      0x26 },
/* 0x49 - PgUp      */ {  0,        0,       0x49,      0x21 },
/* 0x4A - '-'       */ {  0,        0,       0x4A,      0x6D },
/* 0x4B - Left      */ {  0,        0,       0x4B,      0x25 },
/* 0x4C - MID       */ {  0,        0,       0x4C,      0x0C },
/* 0x4D - Right     */ {  0,        0,       0x4D,      0x27 },
/* 0x4E - '+'       */ {  0,        0,       0x4E,      0x6B },
/* 0x4F - End       */ {  0,        0,       0x4F,      0x23 },
/* 0x50 - Down      */ {  0,        0,       0x50,      0x28 },
/* 0x51 - PgDown    */ {  0,        0,       0x51,      0x22 },
/* 0x52 - Insert    */ {  0,        0,       0x52,      0x2D },
/* 0x53 - Del       */ {  0,        0,       0x53,      0x2E },
/* 0x54 - Enter     */ {  0,        0,       0x54,      0x0D },
/* 0x55 - ???       */ {  0,        0,        0,         0   },
/* 0x56 - ???       */ {  0,        0,        0,         0   },
/* 0x57 - F11       */ {  0,        0,       0x57,      0x7A },  
/* 0x58 - F12       */ {  0,        0,       0x58,      0x7B },
/* 0x59 - ???       */ {  0,        0,        0,         0   },
/* 0x5A - ???       */ {  0,        0,        0,         0   },
/* 0x5B - Left Win  */ {  0,        0,       0x5B,      0x5B },	
/* 0x5C - Right Win */ {  0,        0,       0x5C,      0x5C },
/* 0x5D - Apps      */ {  0,        0,       0x5D,      0x5D },
/* 0x5E - Pause     */ {  0,        0,       0x5E,      0x13 }
};

static const KEY_CODE NumKeyMap[] = 
{
    { '0',       0,       0x52,     0x2D },
    { '1',       0,       0x4F,     0x23 },
    { '2',       0,       0x50,     0x28 },
    { '3',       0,       0x51,     0x22 },
    { '4',       0,       0x4B,     0x25 },
    { '5',       0,       0x4C,     0x0C },
    { '6',       0,       0x4D,     0x27 },
    { '7',       0,       0x47,     0x24 },
    { '8',       0,       0x48,     0x26 },
    { '9',       0,       0x49,     0x21 },
};

/******************************************************************************
* 函数名称: static U32 ScanCodeAnalysis(RingQueue* rq)
* 功能说明: 解析循环缓冲队列中的扫描码
* 输入参数: RingQueue* rq     --循环缓冲队列
* 输出参数: 无
* 函数返回: | 动作 | 扫描码 | 虚拟键码 | ASCII 码 |
* 其它说明: 
******************************************************************************/
static U32 ScanCodeAnalysis(RingQueue* rq)
{
    U32 ret = 0; // | 动作 | 扫描码 | 虚拟键码 | ASCII 码 |
    U08 key = 0;
    static U08 key2 = 0;
    static U08 key3 = 0;
    U08 keytype = 0;
    static U08 shift = 0;
    static U08 capslock = 0;
    static U08 numlock = 0;
    KEY_CODE* pKey = NULL;
    U08 index = 0;
    static U08 E0 = 0;
    static U08 E1 = 0;

    // 循环队列 rq 中若没有数据，则退出
    if(!RING_NUMS(rq))
        return 0;

    // 从循环队列 rq 中取出一个数据
    RING_GET(rq, key);

    // 先判断是否是扩展 E0、E1 按键
    if(IS_E1(key))
        E1 = 3;
    else if(IS_E0(key))
        E0 = 2;

    // 优先处理 E0、E1 扩展按键
    if(E1)
    {
        if(2 == E1)
            key2 = key;
        else if(1 == E1)
        {
            key3 = key;
            keytype = KEY_TYPE(key2);
            if(RELEASE == keytype)
                key2 -= 0x80;
            keytype = KEY_TYPE(key3);
            if(RELEASE == keytype)
                key3 -= 0x80;
            if(0x1D == key2 && 0x45 == key3)
                ret = (keytype << 24) | (0x5E << 16) | (0x13 << 8) | 0;
        }
        E1--;
    }
    else if(E0)
    {
        if(1 == E0)
        {
            keytype = KEY_TYPE(key);
            if(RELEASE == keytype)
                key -= 0x80;
            pKey = (KEY_CODE*)KeyMap + key;
            if(pKey->scode == key)      // 扫描码并不一定全部识别，有些未定义的扫描码我们不做处理
                ret = (keytype << 24) | (pKey->scode << 16) | (pKey->vcode << 8) | pKey->ascii1;
        } 
        E0--;
    }
    else
    {
        keytype = KEY_TYPE(key);        // 同一按键的扫描码释放比按下大 0x80，统一一下按键值接下来会比较好处理
        if(RELEASE == keytype)
            key -= 0x80;

        // 先处理一下几个特殊按键状态
        if(IS_SHIFT(key))
            shift = keytype;
        else if(IS_CAPSLOCK(key) && RELEASE == keytype)
            capslock = !capslock;
        else if(IS_NUMLOCKS(key) && RELEASE == keytype)
            numlock = !numlock;

        if(IS_NUM_KEY(key))             // 数字小键盘按键
        {
            for(index = 0; index < sizeof(NumKeyMap)/sizeof(NumKeyMap[0]); index++)
            {
                pKey = (KEY_CODE*)NumKeyMap + index;
                if(pKey->scode == key)
                {
                    if(numlock)
                    {
                        ret = (keytype << 24) | (pKey->scode << 16) | (pKey->vcode << 8) | pKey->ascii1;
                        break;
                    }     
                }
            }
        }
        else                            // 常规按键
        {
            pKey = (KEY_CODE*)&KeyMap[key];
            if(pKey->scode == key)      // 扫描码有效
            {
                if(capslock)
                {
                    if(shift)
                        ret = (keytype << 24) | (pKey->scode << 16) | (pKey->vcode << 8) | pKey->ascii1; // 小写
                    else
                        ret = (keytype << 24) | (pKey->scode << 16) | (pKey->vcode << 8) | pKey->ascii2; // 大写
                }
                else
                {
                    if(shift)
                        ret = (keytype << 24) | (pKey->scode << 16) | (pKey->vcode << 8) | pKey->ascii2; // 大写
                    else
                        ret = (keytype << 24) | (pKey->scode << 16) | (pKey->vcode << 8) | pKey->ascii1; // 小写
                }
            }
        }
    }

    return ret;
}

/******************************************************************************
* 函数名称: U32 SYS_ReadKey(void)
* 功能说明: 读取按键值
* 输入参数: 无
* 输出参数: 无
* 函数返回: 按键值
* 其它说明: 无
******************************************************************************/
U32 SYS_ReadKey(void)
{
    return ScanCodeAnalysis(&keyQueue);
}

/******************************************************************************
* 函数名称: void KeyboardIntHandle(void)
* 功能说明: 键盘中断服务程序
* 输入参数: 无
* 输出参数: 无
* 函数返回: 无
* 其它说明: 
******************************************************************************/
void KeyboardIntHandle(void)
{
    U08 key = 0;
    
    // in al, 0x60  ; 从 0x60 端口读一个字节数据
    asm volatile("inb $0x60, %%al; nop;" :"=a"(key));  
    RING_PUT(key, &keyQueue);
    write_m_EOI();
}
